home *** CD-ROM | disk | FTP | other *** search
- Subject: more expreserve nonsense
- Date: Thu, 10 Jun 93 09:03:29 +0200
- From: Christopher Lott <lott@informatik.uni-kl.de>
- Message-Id: <9306100903.aa19612@chanel.informatik.uni-kl.de>
-
-
- Hi,
-
- The latest is that Sun has released a patch for expreserve in SunOS 4.
- Unfortunately, it doesn't look like they have released anything for
- Solaris yet. I also haven't had a chance to test the patch yet.
- Here is a bit from the new patch:
-
- Patch-ID# 101080-01
- Keywords: CTE5592, ex, security, vi, expreserve
- Synopsis: SunOS 4.1.1 4.1.2 4.1.3: security problem with expreserve
- Date: Jun/09/93
- ...
- SunOS release: 4.1.1 4.1.2 4.1.3
- ...
- Problem Description:
- 1044909 race condition when file is created owned by root.
- 1083183 expreserve can be used to overwite any file.
-
-
- So, because the hole seems to still need to be fixed in Solaris,
- I am sending around updates to the patches that I sent previously.
- Some very sharp people around the world pointed out problems in the
- patches that I sent previously, and correspondingly updated versions
- appear below. Oh yeah, and I added a detailed discussion of how you
- can become root. Should have put that in last time, sorry.
-
- Thanks for your time. This message may be freely redistributed.
-
- chris...
- -----------------
-
- Subject: bug in expreserve/security hole/fixes attached
-
- PATCH ID: 101080-01
- The patch is ONLY available for SunOS 4.1.?
-
- OVERVIEW:
- A bug in the program /usr/lib/expreserve, a standard program delivered
- with SunOS and setuid root, opens a huge security hole. Using this
- program as delivered, any user can overwrite any file in the system
- with no effort and can become root with some cracking skills. Fixes
- are given below for people with and without source code.
-
- AFFECTED SYSTEMS:
- SunOS 4, Solaris 2.1, Solaris 2.2, and Sun derivatives like Solbourne.
-
- Note: It seems that this bug stems from changes which Sun made to BSD's
- expreserve program, and that this hole is therefore restricted to SunOS
- and derivatives. I have confirmation that this hole affects SunOS 4.1.*
- and the Solarises. In Solaris 2.1, expreserve is not setuid but I am
- told that the bug is still there, making an indirect attack possible -
- see below. Solaris 2.2 is also affected; expreserve is set-uid root in
- that release. No word yet on releases prior to SunOS4.
-
- HISTORY:
- This bug was recently published in ``iX'' (a German magazine for UNIX
- and related issues, June 1993, pp. 170-171). One person reports
- hearing of this problem in 1987. People have mailed me to say that
- they reported this bug to Sun in 1991 and 1992, so it's clearly not
- new to Sun. I think it is safe to say that this problem is now well
- known.
-
- WHAT IS EXPRESERVE:
- The expreserve program is invoked by the editor ``vi'' if the editor
- session is killed (e.g., by stopping the editor with ctrl-Z and then
- logging out). The contents of the editor buffer are copied from
- the file ``/var/tmp/ExNNNNN'' and written into a file by the name of
- ``/var/preserve/USER/ExaaaNNNNN'' (where N is a decimal digit). The
- expreserve program is also invoked at boot time to recover any saved
- editor sessions which are in /var/tmp at boot time; the assumption is
- that the editor was killed by a system crash.
-
- THE BUG:
- The security hole is caused by a bug in expreserve rather than an
- oversight. Expreserve attempts to check for existence of the file in
- which it wants to write a saved editor session, but it uses an incorrect
- path name (which happens to begin with the slash character) instead of
- the correct, absolute path name. Therefore the check always succeeds
- (no clash is ever detected) and expreserve happily blasts away using the
- correct file name. The bug can be exploited by creating links to real
- system files and then triggering the expreserve program.
-
- TESTING YOUR VERSION OF EXPRESERVE:
- Start vi and type in a few lines - enough so that the program creates a
- /var/tmp/ExNNNNN file. Stop the editor with ctrl-Z. As *root*, issue this
- command: ``trace /usr/lib/expreserve -a |& grep stat'' and look at the
- output. If the bug is present, you will see a line something like this:
- stat ("/Exaaa09466", 0xf7fff4a0) = -1 ENOENT (No such file or directory)
- I.e., the program looks in root. If the line looks something like this:
- stat ("/var/preserve/USER/Exaaa09466", 0xf7fff4a0) = -1 ENOENT ....
- then your version is not affected by this bug.
-
- A PATCH THAT DOESN'T:
- According to my test (above), Sun's Patch nr. 100251-01 does not correct
- the problem.
-
- HOW TO BECOME ROOT:
- The trick is to overwrite /etc/passwd with a dummy entry for uid 0.
- Since ex doesn't store newlines in the text as newlines in the save
- file, we have to kludge a bit and tell ex to edit a _file_ called
- ``\n\nroot::0:1:cracker:/:/bin:sh\n+::0:0:::\n\n''
- (Notice the line to include NIS passwd information as well. If you
- only have an entry for root, then su doesn't work and you can only
- become root if you have access to the console, assuming that root
- logins on pseudo-ttys are blocked.) Then we suspend ex and figure out
- its pid (1045 say) and the highest used pid (1047 say). With a bit of
- luck and timing, the expreserve process we'll force will have pid
- 1047+2 = 1049. Then ``ln -s /etc/passwd /var/preserve/<yourname>/Exaaa01049''
- and kill -10 1045. (/var/preserve/<yourname> must exist; you can easily
- construct it by running ex two times.) This will make ex spawn off
- expreserve and make it dump the file name and contents in the file
- .../Exaaa01049, i.e. /etc/passwd.
-
- THE SOLARIS 2.1 TWIST:
- Actually, this attack succeeds on all affected systems, but seems
- to be the only way to attack Solaris 2.1. Assuming that the scenario
- works with (symbolic) links in /var/preserve/<user>, a user only has
- to make a number of links in his /var/preserve/<user> directory with
- numbers that are low enough to occur when expreserve is run at reboot,
- dump some editor buffers in /var/tmp and wait until the next reboot.
- Of course, if the machine is accessible, the user can just pull the
- plug and force a reboot that way.
-
- A FIX (NO SOURCE REQUIRED):
- The following procedure closes the security holes, including the one
- in solaris 2.1. The first two commands turn off the setuid bits on the
- critical programs. Then /var/preserve is opened up so that expreserve
- can create directories for users (the only reason why it was setuid root).
- Next, a directory is created for root to avoid trojan-horse attacks -
- a user could create lots of links in root's directory and wait for
- root to kill an editor session. Unlikely but possible. Finally, a
- check is added to /etc/rc?? to prevent reboot-style attacks.
-
- chmod u-s /usr/lib/expreserve
- chmod u-s /usr/lib/exrecover
- chmod 1777 /var/preserve
- mkdir /var/preserve/root
- chmod 700 /var/preserve/root
- touch /var/preserve/root/.do-not-delete-me
-
- Finally, the following command must be executed at boot-time BEFORE
- expreserve is invoked:
- /usr/bin/find /var/preserve '(' ! -type d ! -type f -o \
- -type f -links +1 ')' -exec /bin/rm {} ';'
-
- A GOOD FIX (SOURCE REQUIRED):
- No, I don't know where you can get source to expreserve. We have
- sources from Sun. The following patch fixes the bug. The first
- change is to call the mknext() function with the correct buffer -
- the one in which the entire name of the prospective saved-session
- file is stored, not just the last component. The second change alters
- the call to stat() in mknext() to be a call to lstat(). This prevents
- users from creating garbage files in otherwise unwritable system
- directories by creating and exploiting a link to a nonexistent file.
- For example, a user could create a crontab file for daemon, etc.
-
- Note that my version of expreserve.c seems to be from 4.1.1. In that
- version, the target output file is creat()'ed immediately after a call
- to ``close(1)'' thereby guaranteeing that the new fd is 1. Some changes
- were made in 4.1.3, namely that the file is created using the statement
- ``if ((savfild=creat(savfil, 0600)) < 0) {'' and then the file descriptor
- is used in later operations instead of assuming file descriptor 1.
- I believe this is the race condition alluded to in Sun's patches of
- expreserve. Laura Pearlman suggests changing the creat() to an open():
- ``if ((savfild=open(savfil, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {''
- because this guarantees that no determined cracker can slip in a link
- in that directory between the mknext() and the creat(). Because I
- do not have the 4.1.3 source, I cannot distribute a reliable patch
- that incorporates this knowledge.
-
- Apply the patch to the file expreserve.c (in directory .../usr.bin/ex),
- recompile, relink, and install the program. It appears to be safe
- to leave the setuid bit on once this patch has been applied, but I
- can NOT guarantee that this patch fixes all problems with expreserve.
-
- --snip--
- *** expreserve.c.orig Fri May 28 08:36:51 1993
- --- expreserve.c Wed Jun 9 20:55:06 1993
- ***************
- *** 271,281 ****
- }
-
- /*
- - * File is good. Get a name and create a file for the copy.
- - */
- - mknext(pattern);
- - (void) close(1);
- - /*
- * See if preservation directory for user exists.
- */
-
- --- 271,276 ----
- ***************
- *** 299,304 ****
- --- 294,306 ----
- }
- strcpy (savfil, savdir);
- strcat(savfil, pattern);
- +
- + /*
- + * File is good. Get a name and create a file for the copy.
- + */
- + mknext(savfil);
- + (void) close(1);
- +
- if (creat(savfil, 0600) < 0) {
- if (name == 0)
- perror(savfil);
- ***************
- *** 378,384 ****
- dcp[-1]++;
- } else
- dcp[0]++;
- ! if (stat(cp, &stb) == 0)
- goto whoops;
- }
-
- --- 380,386 ----
- dcp[-1]++;
- } else
- dcp[0]++;
- ! if (lstat(cp, &stb) == 0)
- goto whoops;
- }
-
- --snip--
-
- A RELATED PROBLEM:
- The /etc/rc file as delivered with SunOS 4.1.1 issues this command
- to save editor sessions: ``(cd /tmp; /usr/lib/expreserve -a)''
- However, the editors use /var/tmp. For those who have separate /tmp
- and /var/tmp directories (for example, /tmp as a ram disk), then any
- vi session files are never recovered at boot-time. In our setup, /tmp
- is just a link to /var/tmp, so this hasn't bitten us.
-
- A BETTER SOLUTION?
- Mr Ellis of CERT suggests that the best solution is to simply give up
- root privileges after creating the directory for the user. I have not
- tried to figure out the consequences of this one. Perhaps Sun will
- consider this in their work.
-
- FINAL COMMENT:
- I think the practice of creating a /var/preserve/USER directory is poor.
- Any user can do this and can then happily instigate a denial of service
- attack by filling the corresponding partition to 100%. (I suppose that
- the saving of editor files would still work in that situation, since root
- does the writing, but it's still very unclean.) Why not just leave files
- under /var/expreserve? The name creation has 26^3 possibilities (aaa, aab,
- etc.) so clashing names for a given process ID shouldn't be a problem.
-
- CREDITS:
- Many thanks to the following people:
- Heinrich Welter (author of the article in iX)
- Paul Kurzweil <kurzweil@informatik.uni-kl.de>,
- Alfred Broeckers <broecker@informatik.uni-kl.de>,
- Mikael Pettersson <mpe@ida.liu.se>,
- Klaus-Peter Kossakow <kossakow@rzdspc5.informatik.uni-hamburg.de>,
- Casper Dik <casper@fwi.uva.nl>,
- Daniel Trinkle <trinkle@cs.purdue.edu>,
- Jim Ellis <jte@cert.org>,
- Wolfgang Rupprecht <wolfgang@wsrcc.com>,
- Laura Pearlman <pearlman@monty.rand.org>
-
- ---
- "Christopher Lott lott@informatik.uni-kl.de +49 (631) 205-3334, -3331 Fax"
- "Post: FB Informatik - Bau 57, Universitaet KL, 67653 Kaiserslautern, Germany"
-
-